<?php
namespace WDB\Query;
use WDB,
    WDB\Exception;

/**
 * SQL INSERT query builder
 * 
 * @author Richard Ejem <richard(at)ejem.cz>
 * @package WDB
 * 
 * @property array $columns colname=>value
 * @property Element\TableIdentifier $table
 * @property int $mode duplicity resolving mode (see class constants MODE_*)
 * @property array $ODKUcolumns update columns for ON DUPLICATE KEY UPDATE
 * clause if $mode is UPDATE
 */
class Insert extends Query
{
    /**@var int Enumeration of Insert::MODE_* */
    protected $duplicityMode;
    /**@var array column name=>value for ON DUPLICATE KEY UPDATE clause*/
    protected $ODKUcolumns;
    
    //for oracle, alternative modes are not supported. We will see if there
    //will be implemented a workaround through MERGE or a direct MERGE query will be provided
    //for oracle driver.
    
    /** use plain INSERT INTO - trigger sql error on duplicating unique values; default behavior */
    const UNIQUE = 1;
    /** use REPLACE INTO - replace existing row when saving a new row on duplicating unique values */
    const REPLACE = 2;
    /** use INSERT IGNORE INTO - throw away a new row on duplicating unique values. Use with caution - can lead
     * to unexpected results on tables with multiple unique constraints */
    const IGNORE = 3;
    /** use ON DUPLICATE KEY UPDATE clause - update existing row on duplicating unique values. Use with caution - can lead
     * to unexpected results on tables with multiple unique constraints */
    const UPDATE = 4;
    
    /**
     *
     * @param Element\iTableSource|string target table
     * @param array column name=>value pairs
     * @param int insert mode (Insert::MODE_*)
     */
    public function __construct($table = NULL, $columns = array(), $mode = self::UNIQUE)
    {
        if ($table !== NULL)
        {
            $this->setTable($table);
            $this->setColumns($columns);
            if ($mode == self::UPDATE)
            {
                $this->ODKUsameAsInsert(TRUE);
            }
        }
        $this->duplicityMode = $mode;
    }
    
    // <editor-fold defaultstate="collapsed" desc="INSERT columns">
    /**
     * Add a column name=>value part to the query.
     *
     * @param string column name
     * @param mixed value
     * @return Insert fluent interface
     */
    public function addColumn($column, $value = NULL)
    {
        $this->columns[$column] = $value;
        return $this;
    }
    
    /**
     * Get all column=>value pairs in the query.
     *
     * @return array
     */
    public function getColumns()
    {
        return $this->columns;
    }
    
    /**
     * Set all column=>value pairs in the query.
     *
     * @param array column name=>value pairs
     * @return Insert fluent interface
     */
    public function setColumns($columns)
    {
        $this->columns = $columns;
        return $this;
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Duplicity solving">
    
    /**
     * Get current duplicity solving mode.
     *
     * @return int (Enumeration of Insert::MODE_*)
     */
    public function getMode()
    {
        return $this->duplicityMode;
    }
    
    /**
     * Set current duplicity solving mode.
     *
     * @param int Enumeration of Insert::MODE_*
     * @return Insert fluent interface
     */
    public function setMode($mode)
    {
        $this->duplicityMode = min(4, max(1, $mode));
        return $this;
    }
    
    /**
     * Get column=>value pairs in ON DUPLICATE KEY UPDATE clause.
     *
     * @return Element\iExpression[] column=>value pairs
     */
    public function getODKUColumns()
    {
        return $this->ODKUcolumns;
    }
    
    /**
     * Set column=>value pairs in ON DUPLICATE KEY UPDATE clause.
     *
     * @param Element\iExpression[] column=>value pairs
     * @return Insert fluent interface
     */
    public function setODKUColumns($columns)
    {
        $this->ODKUcolumns = $columns;
        return $this;
    }
    
    /**
     * Create ODKU Columns array that assigns the values to values of the inserting row
     * i.e. ON DUPLICATE KEY UPDATE foo=VALUES(foo), bar=VALUES(bar) in MySQL dialect
     * 
     * @param bool if true, generated columns are immediately bound
     * to ODKU clause for the query
     * @return array ODKU Columns
     */
    public function ODKUsameAsInsert($setNow = FALSE)
    {
        $odku = array();
        foreach (array_keys($this->columns) as $c)
        {
            $odku[$c] = Element\DBFunction::Values($c);
        }
        if ($setNow)
        {
            $this->ODKUcolumns = $odku;
        }
        return $odku;
    }
    // </editor-fold>
}